home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 19
/
Mac Magazin and MacEasy Magazine CD - Issue 19.iso
/
Musik & Kunst
/
Ear Workout 2.1
/
source code
/
ear_calc.cp
< prev
next >
Wrap
Text File
|
1995-12-02
|
8KB
|
267 lines
// ear_calc.cp
// This file contains functions that do number-crunching (plus
// a few functions that do Unix-style I/O to files), but
// nothing specific to the Mac.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
double sin(),cos(),sqrt(),fabs();
#define PI 3.141592653589793
#define NEED_MAC_STUFF 0
#include "ear_prototypes.h"
#include "ear_defines.h"
/*
Returns a random number in [0,1).
*/
double
random_double()
{
long int n1,n2;
do {
n1 = Random();
}while(n1<-32766 || n1>32766);
do {
n2 = Random();
}while(n2<-32766 || n2>32766);
n1 += 32766;
n2 += 32766; /* both in range of 0 to 65532 */
n1 = n1 & 16383; /* avoid problems with sign */
return (n1*65533L+n2)/1.073758204e+09;
}
/* Before calling the following, you must do:
InitGraf(&thePort);
or else use the stdio routines. */
void
init_random()
{
unsigned long t;
int i,n;
/* The following didn't work, same random numbers returned every time: */
/*
GetDateTime(&randSeed);
*/
/* A total kludge: */
GetDateTime(&t);
n = 1 + (t & 1023L);
for (i=1; i<=n; i++) {
Random();
}
}
/* generate a random number from 1 to n */
int
random_integer(int n)
{
int k;
do {
k = random_double()*n+1;
} while (k<1 || k>n);
return k;
}
double
small_integer_ratio()
{
double x,y;
x = small_integer();
y = small_integer();
return x/y;
}
int
small_integer()
{
int n;
n= 1;
while (random_double()<.25) {
++n;
}
return n;
}
/*
The main problem here is that we only have an 8-bit DAC, so we have to
choose between distorting and making waveforms with amplitudes so small
that you can hear the granularity. Waveforms are first normalized
to have unit rms amplitude. Then they are transformed into 8-bit
integers via
128+100*amplitude*waveform
where amplitude is an input parameter, and results outside the range of 0-254
result in clipping.
Global variable wave_table_size should be set by calling routine, unless
reading sample (kind=5).
Amplitude should typically be set to about 0.3 to avoid distortion
when summing the waveforms of four voices.
modified 12 Mar 95 to renormalize just enough to avoid clipping
*/
void
make_wave_table(unsigned char *final_wave_table, //-- storage for final result
double *temp_wave_table, //-- temporary storage
int kind,
double amplitude,
int wave_table_size,
int make_temp_wave_table)
{
int i,garbage;
double x,s,max_value;
static double raw_ampl,avg;
if (make_temp_wave_table) {
if (kind==5) {
FILE *f;
int z;
char line[MAX_STR_LEN];
f = fopen("wave_file","r");
if (f==(FILE *)0) {
bail_out("Error opening file for input\n");
exit(-1);
}
wave_table_size = 0;
fget_line(line,f);
garbage = atoi(line); // pitch offset
for (;;) {
z = fget_line(line,f);
if (z!=0) break;
temp_wave_table[wave_table_size++] = atoi(line);
}
fclose(f);
}
else {
for (i=0; i<wave_table_size; i++) {
switch(kind) {
/****** sine wave ******/
case 1:
x = ((double ) i)/((double) wave_table_size);
s = sin(2.*PI*x);
temp_wave_table[i] = s;
break;
/****** square wave ******/
case 2:
if (i<wave_table_size/2)
temp_wave_table[i] = 1.0;
else
temp_wave_table[i] = -1.0;
break;
/****** square+sine wave ******/
case 3:
if (i<wave_table_size/2)
temp_wave_table[i] = 0.5;
else
temp_wave_table[i] = -0.5;
x = ((double ) i)/((double) wave_table_size);
s = sin(2.*PI*x);
temp_wave_table[i] += 0.5*s;
break;
/****** superimposed harmonics ******/
case 4:
{
int nharm,j;
double fall_off,f,u;
nharm = 10;
fall_off = 0.9;
if (nharm>20) {
bail_out("Error constructing waveform - too many harmonics\n");
exit(-1);
}
x = ((double ) i)/((double) wave_table_size);
temp_wave_table[i] = 0.0;
u = 2.*PI*x;
f = 1.0;
for (j=1; j<=nharm; j++) {
s = sin(u*j);
temp_wave_table[i] += f*s;
f = f*fall_off;
}
}
break;
} /* end case */
} /* end for */
} /* end else clause, i.e. not a sample */
/* normalize: */
raw_ampl = 0.0;
avg = 0.0;
for (i=0; i<wave_table_size; i++) {
double u;
u = temp_wave_table[i];
avg += u;
raw_ampl += u*u;
}
avg = avg/wave_table_size;
raw_ampl = raw_ampl/wave_table_size;
raw_ampl = sqrt(raw_ampl-avg*avg);
max_value = 0.0;
for (i=0; i<wave_table_size; i++) {
if (fabs(temp_wave_table[i]-avg)>max_value)
max_value = fabs(temp_wave_table[i]-avg);
}
if (amplitude*100*max_value/raw_ampl > 120.)
raw_ampl = raw_ampl * (amplitude*100*max_value/raw_ampl/120.);
}//-- end if make_temp_wave_table
for (i=0; i<wave_table_size; i++) {
double u;
u = 128 + amplitude * 100 * (temp_wave_table[i]-avg) / raw_ampl;
if (u>=254) u=254;
if (u<=0) u = 0;
final_wave_table[i] = u;
}
}
int
fget_line(char *line,FILE *f)
{
char *ret_val;
ret_val = fgets(line,MAX_STR_LEN-5,f);
if (ret_val==(char *) 0 || strlen(line)>MAX_STR_LEN-7) {
*line = '\0';
if (strlen(line)>MAX_STR_LEN-7)
fprintf(stderr,"*** error - line too long\n");
return 1;
}
if (line[strlen(line)-1]=='\n')
line[strlen(line)-1] = '\0';
return 0;
}
void
debug_print(char *message)
{
FILE *f;
static int created_file_already = 0;
if (!created_file_already)
f = fopen("errors","w");
else
f = fopen("errors","a");
if (f != (FILE *) 0) {
fprintf(f,"%s",message);
fflush(f);
fclose(f);
created_file_already = 1;
}
}
double
choose_duration(double typical_tempo)
{
double min_duration,tempo,d;
min_duration = .7 * 2000.*60./typical_tempo;
tempo = typical_tempo*(1.+.2*(random_double()+random_double()-1.));
d = 2000.*60./tempo;
while (d<min_duration) {
d *= 2;
}
return d;
}